home *** CD-ROM | disk | FTP | other *** search
/ Aminet 41 / Aminet 41 (2001)(Schatztruhe)[!][Feb 2001].iso / Aminet / dev / c / libiconv_src.lha / tools / cjk_tab_to_h.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-11-07  |  46.6 KB  |  1,544 lines

  1. /*
  2.  * Generates a CJK character set table from a .TXT table as found on
  3.  * ftp.unicode.org or in the X nls directory.
  4.  * Examples:
  5.  *
  6.  *   ./cjk_tab_to_h GB2312.1980-0 gb2312 > gb2312.h < gb2312
  7.  *   ./cjk_tab_to_h JISX0208.1983-0 jisx0208 > jisx0208.h < jis0208
  8.  *   ./cjk_tab_to_h KSC5601.1987-0 ksc5601 > ksc5601.h < ksc5601
  9.  *
  10.  *   ./cjk_tab_to_h GB2312.1980-0 gb2312 > gb2312.h < GB2312.TXT
  11.  *   ./cjk_tab_to_h JISX0208.1983-0 jisx0208 > jisx0208.h < JIS0208.TXT
  12.  *   ./cjk_tab_to_h JISX0212.1990-0 jisx0212 > jisx0212.h < JIS0212.TXT
  13.  *   ./cjk_tab_to_h KSC5601.1987-0 ksc5601 > ksc5601.h < KSC5601.TXT
  14.  *   ./cjk_tab_to_h KSX1001.1992-0 ksc5601 > ksc5601.h < KSX1001.TXT
  15.  *
  16.  *   ./cjk_tab_to_h BIG5 big5 > big5.h < BIG5.TXT
  17.  *
  18.  *   ./cjk_tab_to_h JOHAB johab > johab.h < JOHAB.TXT
  19.  */
  20.  
  21. #include <stdio.h>
  22. #include <stdlib.h>
  23. #include <stdbool.h>
  24. #include <string.h>
  25.  
  26. typedef struct {
  27.   int start;
  28.   int end;
  29. } Block;
  30.  
  31. typedef struct {
  32.   int rows;    /* number of possible values for the 1st byte */
  33.   int cols;    /* number of possible values for the 2nd byte */
  34.   int (*row_byte) (int row); /* returns the 1st byte value for a given row */
  35.   int (*col_byte) (int col); /* returns the 2nd byte value for a given col */
  36.   int (*byte_row) (int byte); /* converts a 1st byte value to a row, else -1 */
  37.   int (*byte_col) (int byte); /* converts a 2nd byte value to a col, else -1 */
  38.   const char* check_row_expr; /* format string for 1st byte value checking */
  39.   const char* check_col_expr; /* format string for 2nd byte value checking */
  40.   const char* byte_row_expr; /* format string for 1st byte value to row */
  41.   const char* byte_col_expr; /* format string for 2nd byte value to col */
  42.   int** charset2uni; /* charset2uni[0..rows-1][0..cols-1] is valid */
  43.   /* You'll understand the terms "row" and "col" when you buy Ken Lunde's book.
  44.      Once a row is fixed, choosing a "col" is the same as choosing a "cell". */
  45.   int* charsetpage; /* charsetpage[0..rows]: how large is a page for a row */
  46.   int ncharsetblocks;
  47.   Block* charsetblocks; /* blocks[0..nblocks-1] */
  48.   int* uni2charset; /* uni2charset[0x0000..0xffff] */
  49. } Encoding;
  50.  
  51. /*
  52.  * Outputs the file title.
  53.  */
  54. static void output_title (const char *charsetname)
  55. {
  56.   printf("\n");
  57.   printf("/*\n");
  58.   printf(" * %s\n", charsetname);
  59.   printf(" */\n");
  60.   printf("\n");
  61. }
  62.  
  63. /*
  64.  * Reads the charset2uni table from standard input.
  65.  */
  66. static void read_table (Encoding* enc)
  67. {
  68.   int row, col, i, i1, i2, c, j;
  69.  
  70.   enc->charset2uni = (int**) malloc(enc->rows*sizeof(int*));
  71.   for (row = 0; row < enc->rows; row++)
  72.     enc->charset2uni[row] = (int*) malloc(enc->cols*sizeof(int));
  73.  
  74.   for (row = 0; row < enc->rows; row++)
  75.     for (col = 0; col < enc->cols; col++)
  76.       enc->charset2uni[row][col] = 0xfffd;
  77.  
  78.   c = getc(stdin);
  79.   ungetc(c,stdin);
  80.   if (c == '#') {
  81.     /* Read a unicode.org style .TXT file. */
  82.     for (;;) {
  83.       c = getc(stdin);
  84.       if (c == EOF)
  85.         break;
  86.       if (c == '\n' || c == ' ' || c == '\t')
  87.         continue;
  88.       if (c == '#') {
  89.         do { c = getc(stdin); } while (!(c == EOF || c == '\n'));
  90.         continue;
  91.       }
  92.       ungetc(c,stdin);
  93.       if (scanf("0x%x", &j) != 1)
  94.         exit(1);
  95.       i1 = j >> 8;
  96.       i2 = j & 0xff;
  97.       row = enc->byte_row(i1);
  98.       col = enc->byte_col(i2);
  99.       if (row < 0 || col < 0) {
  100.         fprintf(stderr, "lost entry for %02x %02x\n", i1, i2);
  101.         exit(1);
  102.       }
  103.       if (scanf(" 0x%x", &enc->charset2uni[row][col]) != 1)
  104.         exit(1);
  105.     }
  106.   } else {
  107.     /* Read a table of hexadecimal Unicode values. */
  108.     for (i1 = 32; i1 < 132; i1++)
  109.       for (i2 = 32; i2 < 132; i2++) {
  110.         i = scanf("%x", &j);
  111.         if (i == EOF)
  112.           goto read_done;
  113.         if (i != 1)
  114.           exit(1);
  115.         if (j < 0 || j == 0xffff)
  116.           j = 0xfffd;
  117.         if (j != 0xfffd) {
  118.           if (enc->byte_row(i1) < 0 || enc->byte_col(i2) < 0) {
  119.             fprintf(stderr, "lost entry at %02x %02x\n", i1, i2);
  120.             exit (1);
  121.           }
  122.           enc->charset2uni[enc->byte_row(i1)][enc->byte_col(i2)] = j;
  123.         }
  124.       }
  125.    read_done: ;
  126.   }
  127. }
  128.  
  129. /*
  130.  * Computes the charsetpage[0..rows] array.
  131.  */
  132. static void find_charset2uni_pages (Encoding* enc)
  133. {
  134.   int row, col;
  135.  
  136.   enc->charsetpage = (int*) malloc((enc->rows+1)*sizeof(int));
  137.  
  138.   for (row = 0; row <= enc->rows; row++)
  139.     enc->charsetpage[row] = 0;
  140.  
  141.   for (row = 0; row < enc->rows; row++) {
  142.     int used = 0;
  143.     for (col = 0; col < enc->cols; col++)
  144.       if (enc->charset2uni[row][col] != 0xfffd)
  145.         used = col+1;
  146.     enc->charsetpage[row] = used;
  147.   }
  148. }
  149.  
  150. /*
  151.  * Fills in nblocks and blocks.
  152.  */
  153. static void find_charset2uni_blocks (Encoding* enc)
  154. {
  155.   int n, row, lastrow;
  156.  
  157.   enc->charsetblocks = (Block*) malloc(enc->rows*sizeof(Block));
  158.  
  159.   n = 0;
  160.   for (row = 0; row < enc->rows; row++)
  161.     if (enc->charsetpage[row] > 0 && (row == 0 || enc->charsetpage[row-1] == 0)) {
  162.       for (lastrow = row; enc->charsetpage[lastrow+1] > 0; lastrow++);
  163.       enc->charsetblocks[n].start = row * enc->cols;
  164.       enc->charsetblocks[n].end = lastrow * enc->cols + enc->charsetpage[lastrow];
  165.       n++;
  166.     }
  167.   enc->ncharsetblocks = n;
  168. }
  169.  
  170. /*
  171.  * Outputs the charset to unicode table and function.
  172.  */
  173. static void output_charset2uni (const char* name, Encoding* enc)
  174. {
  175.   int row, col, lastrow, col_max, i, i1_min, i1_max;
  176.  
  177.   find_charset2uni_pages(enc);
  178.  
  179.   find_charset2uni_blocks(enc);
  180.  
  181.   for (row = 0; row < enc->rows; row++)
  182.     if (enc->charsetpage[row] > 0) {
  183.       if (row == 0 || enc->charsetpage[row-1] == 0) {
  184.         /* Start a new block. */
  185.         for (lastrow = row; enc->charsetpage[lastrow+1] > 0; lastrow++);
  186.         printf("static const unsigned short %s_2uni_page%02x[%d] = {\n",
  187.                name, enc->row_byte(row),
  188.                (lastrow-row) * enc->cols + enc->charsetpage[lastrow]);
  189.       }
  190.       printf("  /""* 0x%02x *""/\n ", enc->row_byte(row));
  191.       col_max = (enc->charsetpage[row+1] > 0 ? enc->cols : enc->charsetpage[row]);
  192.       for (col = 0; col < col_max; col++) {
  193.         printf(" 0x%04x,", enc->charset2uni[row][col]);
  194.         if ((col % 8) == 7 && (col+1 < col_max)) printf("\n ");
  195.       }
  196.       printf("\n");
  197.       if (enc->charsetpage[row+1] == 0) {
  198.         /* End a block. */
  199.         printf("};\n");
  200.       }
  201.     }
  202.   printf("\n");
  203.  
  204.   printf("static int\n");
  205.   printf("%s_mbtowc (conv_t conv, wchar_t *pwc, const unsigned char *s, int n)\n", name);
  206.   printf("{\n");
  207.   printf("  unsigned char c1 = s[0];\n");
  208.   printf("  if (");
  209.   for (i = 0; i < enc->ncharsetblocks; i++) {
  210.     i1_min = enc->row_byte(enc->charsetblocks[i].start / enc->cols);
  211.     i1_max = enc->row_byte((enc->charsetblocks[i].end-1) / enc->cols);
  212.     if (i > 0)
  213.       printf(" || ");
  214.     if (i1_min == i1_max)
  215.       printf("(c1 == 0x%02x)", i1_min);
  216.     else
  217.       printf("(c1 >= 0x%02x && c1 <= 0x%02x)", i1_min, i1_max);
  218.   }
  219.   printf(") {\n");
  220.   printf("    if (n >= 2) {\n");
  221.   printf("      unsigned char c2 = s[1];\n");
  222.   printf("      if (");
  223.   printf(enc->check_col_expr, "c2");
  224.   printf(") {\n");
  225.   printf("        unsigned int i = %d * (", enc->cols);
  226.   printf(enc->byte_row_expr, "c1");
  227.   printf(") + (");
  228.   printf(enc->byte_col_expr, "c2");
  229.   printf(");\n");
  230.   printf("        unsigned short wc = 0xfffd;\n");
  231.   for (i = 0; i < enc->ncharsetblocks; i++) {
  232.     printf("        ");
  233.     if (i > 0)
  234.       printf("} else ");
  235.     if (i < enc->ncharsetblocks-1)
  236.       printf("if (i < %d) ", enc->charsetblocks[i+1].start);
  237.     printf("{\n");
  238.     printf("          if (i < %d)\n", enc->charsetblocks[i].end);
  239.     printf("            wc = %s_2uni_page%02x[i", name, enc->row_byte(enc->charsetblocks[i].start / enc->cols));
  240.     if (enc->charsetblocks[i].start > 0)
  241.       printf("-%d", enc->charsetblocks[i].start);
  242.     printf("];\n");
  243.   }
  244.   printf("        }\n");
  245.   printf("        if (wc != 0xfffd) {\n");
  246.   printf("          *pwc = (wchar_t) wc;\n");
  247.   printf("          return 2;\n");
  248.   printf("        }\n");
  249.   printf("      }\n");
  250.   printf("      return RET_ILSEQ;\n");
  251.   printf("    }\n");
  252.   printf("    return RET_TOOFEW(0);\n");
  253.   printf("  }\n");
  254.   printf("  return RET_ILSEQ;\n");
  255.   printf("}\n");
  256.   printf("\n");
  257. }
  258.  
  259. /*
  260.  * Outputs the charset to unicode table and function.
  261.  * (Suitable if the mapping function is well defined, i.e. has no holes, and
  262.  * is monotonically increasing with small gaps only.)
  263.  */
  264. static void output_charset2uni_noholes_monotonic (const char* name, Encoding* enc)
  265. {
  266.   int row, col, lastrow, r, col_max, i, i1_min, i1_max;
  267.  
  268.   /* Choose stepsize so that stepsize*steps_per_row >= enc->cols, and
  269.      enc->charset2uni[row][col] - enc->charset2uni[row][col/stepsize*stepsize]
  270.      is always < 0x100. */
  271.   int steps_per_row = 2;
  272.   int stepsize = (enc->cols + steps_per_row-1) / steps_per_row;
  273.  
  274.   find_charset2uni_pages(enc);
  275.  
  276.   find_charset2uni_blocks(enc);
  277.  
  278.   for (row = 0; row < enc->rows; row++)
  279.     if (enc->charsetpage[row] > 0) {
  280.       if (row == 0 || enc->charsetpage[row-1] == 0) {
  281.         /* Start a new block. */
  282.         for (lastrow = row; enc->charsetpage[lastrow+1] > 0; lastrow++);
  283.         printf("static const unsigned short %s_2uni_main_page%02x[%d] = {\n ",
  284.                name, enc->row_byte(row),
  285.                steps_per_row*(lastrow-row+1));
  286.         for (r = row; r <= lastrow; r++) {
  287.           for (i = 0; i < steps_per_row; i++)
  288.             printf(" 0x%04x,", enc->charset2uni[r][i*stepsize]);
  289.           if (((r-row) % 4) == 3 && (r < lastrow)) printf("\n ");
  290.         }
  291.         printf("\n");
  292.         printf("};\n");
  293.         printf("static const unsigned char %s_2uni_page%02x[%d] = {\n",
  294.                name, enc->row_byte(row),
  295.                (lastrow-row) * enc->cols + enc->charsetpage[lastrow]);
  296.       }
  297.       printf("  /""* 0x%02x *""/\n ", enc->row_byte(row));
  298.       col_max = (enc->charsetpage[row+1] > 0 ? enc->cols : enc->charsetpage[row]);
  299.       for (col = 0; col < col_max; col++) {
  300.         printf(" 0x%02x,", enc->charset2uni[row][col] - enc->charset2uni[row][col/stepsize*stepsize]);
  301.         if ((col % 8) == 7 && (col+1 < col_max)) printf("\n ");
  302.       }
  303.       printf("\n");
  304.       if (enc->charsetpage[row+1] == 0) {
  305.         /* End a block. */
  306.         printf("};\n");
  307.       }
  308.     }
  309.   printf("\n");
  310.  
  311.   printf("static int\n");
  312.   printf("%s_mbtowc (conv_t conv, wchar_t *pwc, const unsigned char *s, int n)\n", name);
  313.   printf("{\n");
  314.   printf("  unsigned char c1 = s[0];\n");
  315.   printf("  if (");
  316.   for (i = 0; i < enc->ncharsetblocks; i++) {
  317.     i1_min = enc->row_byte(enc->charsetblocks[i].start / enc->cols);
  318.     i1_max = enc->row_byte((enc->charsetblocks[i].end-1) / enc->cols);
  319.     if (i > 0)
  320.       printf(" || ");
  321.     if (i1_min == i1_max)
  322.       printf("(c1 == 0x%02x)", i1_min);
  323.     else
  324.       printf("(c1 >= 0x%02x && c1 <= 0x%02x)", i1_min, i1_max);
  325.   }
  326.   printf(") {\n");
  327.   printf("    if (n >= 2) {\n");
  328.   printf("      unsigned char c2 = s[1];\n");
  329.   printf("      if (");
  330.   printf(enc->check_col_expr, "c2");
  331.   printf(") {\n");
  332.   printf("        unsigned int row = ");
  333.   printf(enc->byte_row_expr, "c1");
  334.   printf(";\n");
  335.   printf("        unsigned int col = ");
  336.   printf(enc->byte_col_expr, "c2");
  337.   printf(";\n");
  338.   printf("        unsigned int i = %d * row + col;\n", enc->cols);
  339.   printf("        unsigned short wc = 0xfffd;\n");
  340.   for (i = 0; i < enc->ncharsetblocks; i++) {
  341.     printf("        ");
  342.     if (i > 0)
  343.       printf("} else ");
  344.     if (i < enc->ncharsetblocks-1)
  345.       printf("if (i < %d) ", enc->charsetblocks[i+1].start);
  346.     printf("{\n");
  347.     printf("          if (i < %d)\n", enc->charsetblocks[i].end);
  348.     printf("            wc = %s_2uni_main_page%02x[%d*", name, enc->row_byte(enc->charsetblocks[i].start / enc->cols), steps_per_row);
  349.     if (enc->charsetblocks[i].start > 0)
  350.       printf("(row-%d)", enc->charsetblocks[i].start / enc->cols);
  351.     else
  352.       printf("row");
  353.     printf("+");
  354.     if (steps_per_row == 2)
  355.       printf("(col>=%d?1:0)", stepsize);
  356.     else
  357.       printf("col/%d", stepsize);
  358.     printf("] + %s_2uni_page%02x[i", name, enc->row_byte(enc->charsetblocks[i].start / enc->cols));
  359.     if (enc->charsetblocks[i].start > 0)
  360.       printf("-%d", enc->charsetblocks[i].start);
  361.     printf("];\n");
  362.   }
  363.   printf("        }\n");
  364.   printf("        if (wc != 0xfffd) {\n");
  365.   printf("          *pwc = (wchar_t) wc;\n");
  366.   printf("          return 2;\n");
  367.   printf("        }\n");
  368.   printf("      }\n");
  369.   printf("      return RET_ILSEQ;\n");
  370.   printf("    }\n");
  371.   printf("    return RET_TOOFEW(0);\n");
  372.   printf("  }\n");
  373.   printf("  return RET_ILSEQ;\n");
  374.   printf("}\n");
  375.   printf("\n");
  376. }
  377.  
  378. /*
  379.  * Computes the uni2charset[0x0000..0xffff] array.
  380.  */
  381. static void invert (Encoding* enc)
  382. {
  383.   int row, col, j;
  384.  
  385.   enc->uni2charset = (int*) malloc(0x10000*sizeof(int));
  386.  
  387.   for (j = 0; j < 0x10000; j++)
  388.     enc->uni2charset[j] = 0;
  389.  
  390.   for (row = 0; row < enc->rows; row++)
  391.     for (col = 0; col < enc->cols; col++) {
  392.       j = enc->charset2uni[row][col];
  393.       if (j != 0xfffd)
  394.         enc->uni2charset[j] = 0x100 * enc->row_byte(row) + enc->col_byte(col);
  395.     }
  396. }
  397.  
  398. /*
  399.  * Outputs the unicode to charset table and function, using a linear array.
  400.  * (Suitable if the table is dense.)
  401.  */
  402. static void output_uni2charset_dense (const char* name, Encoding* enc)
  403. {
  404.   /* Like in 8bit_tab_to_h.c */
  405.   bool pages[0x100];
  406.   int line[0x2000];
  407.   int tableno;
  408.   struct { int minline; int maxline; int usecount; } tables[0x2000];
  409.   bool first;
  410.   int row, col, j, p, j1, j2, t;
  411.  
  412.   for (p = 0; p < 0x100; p++)
  413.     pages[p] = false;
  414.   for (row = 0; row < enc->rows; row++)
  415.     for (col = 0; col < enc->cols; col++) {
  416.       j = enc->charset2uni[row][col];
  417.       if (j != 0xfffd)
  418.         pages[j>>8] = true;
  419.     }
  420.   for (j1 = 0; j1 < 0x2000; j1++) {
  421.     bool all_invalid = true;
  422.     for (j2 = 0; j2 < 8; j2++) {
  423.       j = 8*j1+j2;
  424.       if (enc->uni2charset[j] != 0)
  425.         all_invalid = false;
  426.     }
  427.     if (all_invalid)
  428.       line[j1] = -1;
  429.     else
  430.       line[j1] = 0;
  431.   }
  432.   tableno = 0;
  433.   for (j1 = 0; j1 < 0x2000; j1++) {
  434.     if (line[j1] >= 0) {
  435.       if (tableno > 0
  436.           && ((j1 > 0 && line[j1-1] == tableno-1)
  437.               || ((tables[tableno-1].maxline >> 5) == (j1 >> 5)
  438.                   && j1 - tables[tableno-1].maxline <= 8))) {
  439.         line[j1] = tableno-1;
  440.         tables[tableno-1].maxline = j1;
  441.       } else {
  442.         tableno++;
  443.         line[j1] = tableno-1;
  444.         tables[tableno-1].minline = tables[tableno-1].maxline = j1;
  445.       }
  446.     }
  447.   }
  448.   for (t = 0; t < tableno; t++) {
  449.     tables[t].usecount = 0;
  450.     j1 = 8*tables[t].minline;
  451.     j2 = 8*(tables[t].maxline+1);
  452.     for (j = j1; j < j2; j++)
  453.       if (enc->uni2charset[j] != 0)
  454.         tables[t].usecount++;
  455.   }
  456.   {
  457.     p = -1;
  458.     for (t = 0; t < tableno; t++)
  459.       if (tables[t].usecount > 1) {
  460.         p = tables[t].minline >> 5;
  461.         printf("static const unsigned short %s_page%02x[%d] = {\n", name, p, 8*(tables[t].maxline-tables[t].minline+1));
  462.         for (j1 = tables[t].minline; j1 <= tables[t].maxline; j1++) {
  463.           if ((j1 % 0x20) == 0 && j1 > tables[t].minline)
  464.             printf("  /* 0x%04x */\n", 8*j1);
  465.           printf(" ");
  466.           for (j2 = 0; j2 < 8; j2++) {
  467.             j = 8*j1+j2;
  468.             printf(" 0x%04x,", enc->uni2charset[j]);
  469.           }
  470.           printf(" /*0x%02x-0x%02x*/\n", 8*(j1 % 0x20), 8*(j1 % 0x20)+7);
  471.         }
  472.         printf("};\n");
  473.       }
  474.     if (p >= 0)
  475.       printf("\n");
  476.   }
  477.   printf("static int\n%s_wctomb (conv_t conv, unsigned char *r, wchar_t wc, int n)\n", name);
  478.   printf("{\n");
  479.   printf("  if (n >= 2) {\n");
  480.   printf("    unsigned short c = 0;\n");
  481.   first = true;
  482.   for (j1 = 0; j1 < 0x2000;) {
  483.     t = line[j1];
  484.     for (j2 = j1; j2 < 0x2000 && line[j2] == t; j2++);
  485.     if (t >= 0) {
  486.       if (j1 != tables[t].minline) abort();
  487.       if (j2 > tables[t].maxline+1) abort();
  488.       j2 = tables[t].maxline+1;
  489.       if (first)
  490.         printf("    ");
  491.       else
  492.         printf("    else ");
  493.       first = false;
  494.       if (tables[t].usecount == 0) abort();
  495.       if (tables[t].usecount == 1) {
  496.         if (j2 != j1+1) abort();
  497.         for (j = 8*j1; j < 8*j2; j++)
  498.           if (enc->uni2charset[j] != 0) {
  499.             printf("if (wc == 0x%04x)\n      c = 0x%02x;\n", j, enc->uni2charset[j]);
  500.             break;
  501.           }
  502.       } else {
  503.         if (j1 == 0) {
  504.           printf("if (wc < 0x%04x)", 8*j2);
  505.         } else {
  506.           printf("if (wc >= 0x%04x && wc < 0x%04x)", 8*j1, 8*j2);
  507.         }
  508.         printf("\n      c = %s_page%02x[wc", name, j1 >> 5);
  509.         if (tables[t].minline > 0)
  510.           printf("-0x%04x", 8*j1);
  511.         printf("];\n");
  512.       }
  513.     }
  514.     j1 = j2;
  515.   }
  516.   printf("    if (c != 0) {\n");
  517.   printf("      r[0] = (c >> 8); r[1] = (c & 0xff);\n");
  518.   printf("      return 2;\n");
  519.   printf("    }\n");
  520.   printf("    return RET_ILSEQ;\n");
  521.   printf("  }\n");
  522.   printf("  return RET_TOOSMALL;\n");
  523.   printf("}\n");
  524. }
  525.  
  526. /*
  527.  * Outputs the unicode to charset table and function, using a packed array.
  528.  * (Suitable if the table is sparse.)
  529.  * The argument 'monotonic' may be set to true if the mapping is monotonically
  530.  * increasing with small gaps only.
  531.  */
  532. static void output_uni2charset_sparse (const char* name, Encoding* enc, bool monotonic)
  533. {
  534.   bool pages[0x100];
  535.   Block pageblocks[0x100]; int npageblocks;
  536.   int indx2charset[0x10000];
  537.   int summary_indx[0x1000];
  538.   int summary_used[0x1000];
  539.   int i, row, col, j, p, j1, j2, indx;
  540.   /* for monotonic: */
  541.   int log2_stepsize = (!strcmp(name,"uhc_2") ? 6 : 7);
  542.   int stepsize = 1 << log2_stepsize;
  543.   int indxsteps;
  544.  
  545.   /* Fill pages[0x100]. */
  546.   for (p = 0; p < 0x100; p++)
  547.     pages[p] = false;
  548.   for (row = 0; row < enc->rows; row++)
  549.     for (col = 0; col < enc->cols; col++) {
  550.       j = enc->charset2uni[row][col];
  551.       if (j != 0xfffd)
  552.         pages[j>>8] = true;
  553.     }
  554.  
  555. #if 0
  556.   for (p = 0; p < 0x100; p++)
  557.     if (pages[p]) {
  558.       printf("static const unsigned short %s_page%02x[256] = {\n", name, p);
  559.       for (j1 = 0; j1 < 32; j1++) {
  560.         printf("  ");
  561.         for (j2 = 0; j2 < 8; j2++)
  562.           printf("0x%04x, ", enc->uni2charset[256*p+8*j1+j2]);
  563.         printf("/""*0x%02x-0x%02x*""/\n", 8*j1, 8*j1+7);
  564.       }
  565.       printf("};\n");
  566.     }
  567.   printf("\n");
  568. #endif
  569.  
  570.   /* Fill summary_indx[] and summary_used[]. */
  571.   indx = 0;
  572.   for (j1 = 0; j1 < 0x1000; j1++) {
  573.     summary_indx[j1] = indx;
  574.     summary_used[j1] = 0;
  575.     for (j2 = 0; j2 < 16; j2++) {
  576.       j = 16*j1+j2;
  577.       if (enc->uni2charset[j] != 0) {
  578.         indx2charset[indx++] = enc->uni2charset[j];
  579.         summary_used[j1] |= (1 << j2);
  580.       }
  581.     }
  582.   }
  583.  
  584.   /* Fill npageblocks and pageblocks[]. */
  585.   npageblocks = 0;
  586.   for (p = 0; p < 0x100; ) {
  587.     if (pages[p] && (p == 0 || !pages[p-1])) {
  588.       pageblocks[npageblocks].start = 16*p;
  589.       do p++; while (p < 0x100 && pages[p]);
  590.       j1 = 16*p;
  591.       while (summary_used[j1-1] == 0) j1--;
  592.       pageblocks[npageblocks].end = j1;
  593.       npageblocks++;
  594.     } else
  595.       p++;
  596.   }
  597.  
  598.   if (monotonic) {
  599.     indxsteps = (indx + stepsize-1) / stepsize;
  600.     printf("static const unsigned short %s_2charset_main[%d] = {\n", name, indxsteps);
  601.     for (i = 0; i < indxsteps; ) {
  602.       if ((i % 8) == 0) printf(" ");
  603.       printf(" 0x%04x,", indx2charset[i*stepsize]);
  604.       i++;
  605.       if ((i % 8) == 0 || i == indxsteps) printf("\n");
  606.     }
  607.     printf("};\n");
  608.     printf("static const unsigned char %s_2charset[%d] = {\n", name, indx);
  609.     for (i = 0; i < indx; ) {
  610.       if ((i % 8) == 0) printf(" ");
  611.       printf(" 0x%02x,", indx2charset[i] - indx2charset[i/stepsize*stepsize]);
  612.       i++;
  613.       if ((i % 8) == 0 || i == indx) printf("\n");
  614.     }
  615.     printf("};\n");
  616.   } else {
  617.     printf("static const unsigned short %s_2charset[%d] = {\n", name, indx);
  618.     for (i = 0; i < indx; ) {
  619.       if ((i % 8) == 0) printf(" ");
  620.       printf(" 0x%04x,", indx2charset[i]);
  621.       i++;
  622.       if ((i % 8) == 0 || i == indx) printf("\n");
  623.     }
  624.     printf("};\n");
  625.   }
  626.   printf("\n");
  627.   for (i = 0; i < npageblocks; i++) {
  628.     printf("static const Summary16 %s_uni2indx_page%02x[%d] = {\n", name,
  629.            pageblocks[i].start/16, pageblocks[i].end-pageblocks[i].start);
  630.     for (j1 = pageblocks[i].start; j1 < pageblocks[i].end; ) {
  631.       if (((16*j1) % 0x100) == 0) printf("  /""* 0x%04x *""/\n", 16*j1);
  632.       if ((j1 % 4) == 0) printf(" ");
  633.       printf(" { %4d, 0x%04x },", summary_indx[j1], summary_used[j1]);
  634.       j1++;
  635.       if ((j1 % 4) == 0 || j1 == pageblocks[i].end) printf("\n");
  636.     }
  637.     printf("};\n");
  638.   }
  639.   printf("\n");
  640.  
  641.   printf("static int\n");
  642.   printf("%s_wctomb (conv_t conv, unsigned char *r, wchar_t wc, int n)\n", name);
  643.   printf("{\n");
  644.   printf("  if (n >= 2) {\n");
  645.   printf("    const Summary16 *summary = NULL;\n");
  646.   for (i = 0; i < npageblocks; i++) {
  647.     printf("    ");
  648.     if (i > 0)
  649.       printf("else ");
  650.     printf("if (wc >= 0x%04x && wc < 0x%04x)\n",
  651.            16*pageblocks[i].start, 16*pageblocks[i].end);
  652.     printf("      summary = &%s_uni2indx_page%02x[(wc>>4)", name,
  653.            pageblocks[i].start/16);
  654.     if (pageblocks[i].start > 0)
  655.       printf("-0x%03x", pageblocks[i].start);
  656.     printf("];\n");
  657.   }
  658.   printf("    if (summary) {\n");
  659.   printf("      unsigned short used = summary->used;\n");
  660.   printf("      unsigned int i = wc & 0x0f;\n");
  661.   printf("      if (used & ((unsigned short) 1 << i)) {\n");
  662.   printf("        unsigned short c;\n");
  663.   printf("        /* Keep in `used' only the bits 0..i-1. */\n");
  664.   printf("        used &= ((unsigned short) 1 << i) - 1;\n");
  665.   printf("        /* Add `summary->indx' and the number of bits set in `used'. */\n");
  666.   printf("        used = (used & 0x5555) + ((used & 0xaaaa) >> 1);\n");
  667.   printf("        used = (used & 0x3333) + ((used & 0xcccc) >> 2);\n");
  668.   printf("        used = (used & 0x0f0f) + ((used & 0xf0f0) >> 4);\n");
  669.   printf("        used = (used & 0x00ff) + (used >> 8);\n");
  670.   if (monotonic) {
  671.     printf("        used += summary->indx;\n");
  672.     printf("        c = %s_2charset_main[used>>%d] + %s_2charset[used];\n", name, log2_stepsize, name);
  673.   } else
  674.     printf("        c = %s_2charset[summary->indx + used];\n", name);
  675.   printf("        r[0] = (c >> 8); r[1] = (c & 0xff);\n");
  676.   printf("        return 2;\n");
  677.   printf("      }\n");
  678.   printf("    }\n");
  679.   printf("    return RET_ILSEQ;\n");
  680.   printf("  }\n");
  681.   printf("  return RET_TOOSMALL;\n");
  682.   printf("}\n");
  683. }
  684.  
  685. /* ISO-2022/EUC specifics */
  686.  
  687. static int row_byte_normal (int row) { return 0x21+row; }
  688. static int col_byte_normal (int col) { return 0x21+col; }
  689. static int byte_row_normal (int byte) { return byte-0x21; }
  690. static int byte_col_normal (int byte) { return byte-0x21; }
  691.  
  692. static void do_normal (const char* name)
  693. {
  694.   Encoding enc;
  695.  
  696.   enc.rows = 94;
  697.   enc.cols = 94;
  698.   enc.row_byte = row_byte_normal;
  699.   enc.col_byte = col_byte_normal;
  700.   enc.byte_row = byte_row_normal;
  701.   enc.byte_col = byte_col_normal;
  702.   enc.check_row_expr = "%1$s >= 0x21 && %1$s < 0x7f";
  703.   enc.check_col_expr = "%1$s >= 0x21 && %1$s < 0x7f";
  704.   enc.byte_row_expr = "%1$s - 0x21";
  705.   enc.byte_col_expr = "%1$s - 0x21";
  706.  
  707.   read_table(&enc);
  708.   output_charset2uni(name,&enc);
  709.   invert(&enc); output_uni2charset_sparse(name,&enc,false);
  710. }
  711.  
  712. /* Note: On first sight, the jisx0212_2charset[] table seems to be in order,
  713.    starting from the charset=0x3021/uni=0x4e02 pair. But it's only mostly in
  714.    order. There are 75 out-of-order values, scattered all throughout the table.
  715.  */
  716.  
  717. static void do_normal_only_charset2uni (const char* name)
  718. {
  719.   Encoding enc;
  720.  
  721.   enc.rows = 94;
  722.   enc.cols = 94;
  723.   enc.row_byte = row_byte_normal;
  724.   enc.col_byte = col_byte_normal;
  725.   enc.byte_row = byte_row_normal;
  726.   enc.byte_col = byte_col_normal;
  727.   enc.check_row_expr = "%1$s >= 0x21 && %1$s < 0x7f";
  728.   enc.check_col_expr = "%1$s >= 0x21 && %1$s < 0x7f";
  729.   enc.byte_row_expr = "%1$s - 0x21";
  730.   enc.byte_col_expr = "%1$s - 0x21";
  731.  
  732.   read_table(&enc);
  733.   output_charset2uni(name,&enc);
  734. }
  735.  
  736. /* CNS 11643 specifics - trick to put two tables into one */
  737.  
  738. static int row_byte_cns11643 (int row) {
  739.   return 0x100 * (row / 94) + (row % 94) + 0x21;
  740. }
  741. static int byte_row_cns11643 (int byte) {
  742.   return (byte >= 0x100 && byte < 0x200 ? byte-0x121 :
  743.           byte >= 0x200 && byte < 0x300 ? byte-0x221+94 :
  744.           byte >= 0x300 && byte < 0x400 ? byte-0x321+2*94 :
  745.           -1);
  746. }
  747.  
  748. static void do_cns11643_only_uni2charset (const char* name)
  749. {
  750.   Encoding enc;
  751.   int j, x;
  752.  
  753.   enc.rows = 3*94;
  754.   enc.cols = 94;
  755.   enc.row_byte = row_byte_cns11643;
  756.   enc.col_byte = col_byte_normal;
  757.   enc.byte_row = byte_row_cns11643;
  758.   enc.byte_col = byte_col_normal;
  759.   enc.check_row_expr = "%1$s >= 0x21 && %1$s < 0x7f";
  760.   enc.check_col_expr = "%1$s >= 0x21 && %1$s < 0x7f";
  761.   enc.byte_row_expr = "%1$s - 0x21";
  762.   enc.byte_col_expr = "%1$s - 0x21";
  763.  
  764.   read_table(&enc);
  765.   invert(&enc);
  766.   /* Move the 2 plane bits into the unused bits 15 and 7. */
  767.   for (j = 0; j < 0x10000; j++) {
  768.     x = enc.uni2charset[j];
  769.     if (x != 0) {
  770.       if (x & 0x8080) abort();
  771.       switch (x >> 16) {
  772.         case 0: /* plane 1 */ x = (x & 0xffff) | 0x0000; break;
  773.         case 1: /* plane 2 */ x = (x & 0xffff) | 0x0080; break;
  774.         case 2: /* plane 3 */ x = (x & 0xffff) | 0x8000; break;
  775.         default: abort();
  776.       }
  777.       enc.uni2charset[j] = x;
  778.     }
  779.   }
  780.   output_uni2charset_sparse(name,&enc,false);
  781. }
  782.  
  783. /* GBK specifics */
  784.  
  785. static int row_byte_gbk1 (int row) {
  786.   return 0x81+row;
  787. }
  788. static int col_byte_gbk1 (int col) {
  789.   return (col >= 0x3f ? 0x41 : 0x40) + col;
  790. }
  791. static int byte_row_gbk1 (int byte) {
  792.   if (byte >= 0x81 && byte < 0xff)
  793.     return byte-0x81;
  794.   else
  795.     return -1;
  796. }
  797. static int byte_col_gbk1 (int byte) {
  798.   if (byte >= 0x40 && byte < 0x7f)
  799.     return byte-0x40;
  800.   else if (byte >= 0x80 && byte < 0xff)
  801.     return byte-0x41;
  802.   else
  803.     return -1;
  804. }
  805.  
  806. static void do_gbk1 (const char* name)
  807. {
  808.   Encoding enc;
  809.  
  810.   enc.rows = 126;
  811.   enc.cols = 190;
  812.   enc.row_byte = row_byte_gbk1;
  813.   enc.col_byte = col_byte_gbk1;
  814.   enc.byte_row = byte_row_gbk1;
  815.   enc.byte_col = byte_col_gbk1;
  816.   enc.check_row_expr = "%1$s >= 0x81 && %1$s < 0xff";
  817.   enc.check_col_expr = "(%1$s >= 0x40 && %1$s < 0x7f) || (%1$s >= 0x80 && %1$s < 0xff)";
  818.   enc.byte_row_expr = "%1$s - 0x81";
  819.   enc.byte_col_expr = "%1$s - (%1$s >= 0x80 ? 0x41 : 0x40)";
  820.  
  821.   read_table(&enc);
  822.   output_charset2uni(name,&enc);
  823.   invert(&enc); output_uni2charset_dense(name,&enc);
  824. }
  825.  
  826. static void do_gbk1_only_charset2uni (const char* name)
  827. {
  828.   Encoding enc;
  829.  
  830.   enc.rows = 126;
  831.   enc.cols = 190;
  832.   enc.row_byte = row_byte_gbk1;
  833.   enc.col_byte = col_byte_gbk1;
  834.   enc.byte_row = byte_row_gbk1;
  835.   enc.byte_col = byte_col_gbk1;
  836.   enc.check_row_expr = "%1$s >= 0x81 && %1$s < 0xff";
  837.   enc.check_col_expr = "(%1$s >= 0x40 && %1$s < 0x7f) || (%1$s >= 0x80 && %1$s < 0xff)";
  838.   enc.byte_row_expr = "%1$s - 0x81";
  839.   enc.byte_col_expr = "%1$s - (%1$s >= 0x80 ? 0x41 : 0x40)";
  840.  
  841.   read_table(&enc);
  842.   output_charset2uni(name,&enc);
  843. }
  844.  
  845. static int row_byte_gbk2 (int row) {
  846.   return 0x81+row;
  847. }
  848. static int col_byte_gbk2 (int col) {
  849.   return (col >= 0x3f ? 0x41 : 0x40) + col;
  850. }
  851. static int byte_row_gbk2 (int byte) {
  852.   if (byte >= 0x81 && byte < 0xff)
  853.     return byte-0x81;
  854.   else
  855.     return -1;
  856. }
  857. static int byte_col_gbk2 (int byte) {
  858.   if (byte >= 0x40 && byte < 0x7f)
  859.     return byte-0x40;
  860.   else if (byte >= 0x80 && byte < 0xa1)
  861.     return byte-0x41;
  862.   else
  863.     return -1;
  864. }
  865.  
  866. static void do_gbk2_only_charset2uni (const char* name)
  867. {
  868.   Encoding enc;
  869.  
  870.   enc.rows = 126;
  871.   enc.cols = 96;
  872.   enc.row_byte = row_byte_gbk2;
  873.   enc.col_byte = col_byte_gbk2;
  874.   enc.byte_row = byte_row_gbk2;
  875.   enc.byte_col = byte_col_gbk2;
  876.   enc.check_row_expr = "%1$s >= 0x81 && %1$s < 0xff";
  877.   enc.check_col_expr = "(%1$s >= 0x40 && %1$s < 0x7f) || (%1$s >= 0x80 && %1$s < 0xa1)";
  878.   enc.byte_row_expr = "%1$s - 0x81";
  879.   enc.byte_col_expr = "%1$s - (%1$s >= 0x80 ? 0x41 : 0x40)";
  880.  
  881.   read_table(&enc);
  882.   output_charset2uni(name,&enc);
  883. }
  884.  
  885. static void do_gbk1_only_uni2charset (const char* name)
  886. {
  887.   Encoding enc;
  888.  
  889.   enc.rows = 126;
  890.   enc.cols = 190;
  891.   enc.row_byte = row_byte_gbk1;
  892.   enc.col_byte = col_byte_gbk1;
  893.   enc.byte_row = byte_row_gbk1;
  894.   enc.byte_col = byte_col_gbk1;
  895.   enc.check_row_expr = "%1$s >= 0x81 && %1$s < 0xff";
  896.   enc.check_col_expr = "(%1$s >= 0x40 && %1$s < 0x7f) || (%1$s >= 0x80 && %1$s < 0xff)";
  897.   enc.byte_row_expr = "%1$s - 0x81";
  898.   enc.byte_col_expr = "%1$s - (%1$s >= 0x80 ? 0x41 : 0x40)";
  899.  
  900.   read_table(&enc);
  901.   invert(&enc); output_uni2charset_sparse(name,&enc,false);
  902. }
  903.  
  904. /* KSC 5601 specifics */
  905.  
  906. /*
  907.  * Reads the charset2uni table from standard input.
  908.  */
  909. static void read_table_ksc5601 (Encoding* enc)
  910. {
  911.   int row, col, i, i1, i2, c, j;
  912.  
  913.   enc->charset2uni = (int**) malloc(enc->rows*sizeof(int*));
  914.   for (row = 0; row < enc->rows; row++)
  915.     enc->charset2uni[row] = (int*) malloc(enc->cols*sizeof(int));
  916.  
  917.   for (row = 0; row < enc->rows; row++)
  918.     for (col = 0; col < enc->cols; col++)
  919.       enc->charset2uni[row][col] = 0xfffd;
  920.  
  921.   c = getc(stdin);
  922.   ungetc(c,stdin);
  923.   if (c == '#') {
  924.     /* Read a unicode.org style .TXT file. */
  925.     for (;;) {
  926.       c = getc(stdin);
  927.       if (c == EOF)
  928.         break;
  929.       if (c == '\n' || c == ' ' || c == '\t')
  930.         continue;
  931.       if (c == '#') {
  932.         do { c = getc(stdin); } while (!(c == EOF || c == '\n'));
  933.         continue;
  934.       }
  935.       ungetc(c,stdin);
  936.       if (scanf("0x%x", &j) != 1)
  937.         exit(1);
  938.       i1 = j >> 8;
  939.       i2 = j & 0xff;
  940.       if (scanf(" 0x%x", &j) != 1)
  941.         exit(1);
  942.       /* Take only the range covered by KS C 5601.1987-0 = KS C 5601.1989-0
  943.          = KS X 1001.1992, ignore the rest. */
  944.       if (!(i1 >= 128+33 && i1 < 128+127 && i2 >= 128+33 && i2 < 128+127))
  945.         continue;  /* KSC5601 specific */
  946.       i1 &= 0x7f;  /* KSC5601 specific */
  947.       i2 &= 0x7f;  /* KSC5601 specific */
  948.       row = enc->byte_row(i1);
  949.       col = enc->byte_col(i2);
  950.       if (row < 0 || col < 0) {
  951.         fprintf(stderr, "lost entry for %02x %02x\n", i1, i2);
  952.         exit(1);
  953.       }
  954.       enc->charset2uni[row][col] = j;
  955.     }
  956.   } else {
  957.     /* Read a table of hexadecimal Unicode values. */
  958.     for (i1 = 33; i1 < 127; i1++)
  959.       for (i2 = 33; i2 < 127; i2++) {
  960.         i = scanf("%x", &j);
  961.         if (i == EOF)
  962.           goto read_done;
  963.         if (i != 1)
  964.           exit(1);
  965.         if (j < 0 || j == 0xffff)
  966.           j = 0xfffd;
  967.         if (j != 0xfffd) {
  968.           if (enc->byte_row(i1) < 0 || enc->byte_col(i2) < 0) {
  969.             fprintf(stderr, "lost entry at %02x %02x\n", i1, i2);
  970.             exit (1);
  971.           }
  972.           enc->charset2uni[enc->byte_row(i1)][enc->byte_col(i2)] = j;
  973.         }
  974.       }
  975.    read_done: ;
  976.   }
  977. }
  978.  
  979. static void do_ksc5601 (const char* name)
  980. {
  981.   Encoding enc;
  982.  
  983.   enc.rows = 94;
  984.   enc.cols = 94;
  985.   enc.row_byte = row_byte_normal;
  986.   enc.col_byte = col_byte_normal;
  987.   enc.byte_row = byte_row_normal;
  988.   enc.byte_col = byte_col_normal;
  989.   enc.check_row_expr = "%1$s >= 0x21 && %1$s < 0x7f";
  990.   enc.check_col_expr = "%1$s >= 0x21 && %1$s < 0x7f";
  991.   enc.byte_row_expr = "%1$s - 0x21";
  992.   enc.byte_col_expr = "%1$s - 0x21";
  993.  
  994.   read_table_ksc5601(&enc);
  995.   output_charset2uni(name,&enc);
  996.   invert(&enc); output_uni2charset_sparse(name,&enc,false);
  997. }
  998.  
  999. /* UHC specifics */
  1000.  
  1001. /* UHC part 1: 0x{81..A0}{41..5A,61..7A,81..FE} */
  1002.  
  1003. static int row_byte_uhc_1 (int row) {
  1004.   return 0x81 + row;
  1005. }
  1006. static int col_byte_uhc_1 (int col) {
  1007.   return (col >= 0x34 ? 0x4d : col >= 0x1a ? 0x47 : 0x41) + col;
  1008. }
  1009. static int byte_row_uhc_1 (int byte) {
  1010.   if (byte >= 0x81 && byte < 0xa1)
  1011.     return byte-0x81;
  1012.   else
  1013.     return -1;
  1014. }
  1015. static int byte_col_uhc_1 (int byte) {
  1016.   if (byte >= 0x41 && byte < 0x5b)
  1017.     return byte-0x41;
  1018.   else if (byte >= 0x61 && byte < 0x7b)
  1019.     return byte-0x47;
  1020.   else if (byte >= 0x81 && byte < 0xff)
  1021.     return byte-0x4d;
  1022.   else
  1023.     return -1;
  1024. }
  1025.  
  1026. static void do_uhc_1 (const char* name)
  1027. {
  1028.   Encoding enc;
  1029.  
  1030.   enc.rows = 32;
  1031.   enc.cols = 178;
  1032.   enc.row_byte = row_byte_uhc_1;
  1033.   enc.col_byte = col_byte_uhc_1;
  1034.   enc.byte_row = byte_row_uhc_1;
  1035.   enc.byte_col = byte_col_uhc_1;
  1036.   enc.check_row_expr = "(%1$s >= 0x81 && %1$s < 0xa1)";
  1037.   enc.check_col_expr = "(%1$s >= 0x41 && %1$s < 0x5b) || (%1$s >= 0x61 && %1$s < 0x7b) || (%1$s >= 0x81 && %1$s < 0xff)";
  1038.   enc.byte_row_expr = "%1$s - 0x81";
  1039.   enc.byte_col_expr = "%1$s - (%1$s >= 0x81 ? 0x4d : %1$s >= 0x61 ? 0x47 : 0x41)";
  1040.  
  1041.   read_table(&enc);
  1042.   output_charset2uni_noholes_monotonic(name,&enc);
  1043.   invert(&enc); output_uni2charset_sparse(name,&enc,true);
  1044. }
  1045.  
  1046. /* UHC part 2: 0x{A1..C6}{41..5A,61..7A,81..A0} */
  1047.  
  1048. static int row_byte_uhc_2 (int row) {
  1049.   return 0xa1 + row;
  1050. }
  1051. static int col_byte_uhc_2 (int col) {
  1052.   return (col >= 0x34 ? 0x4d : col >= 0x1a ? 0x47 : 0x41) + col;
  1053. }
  1054. static int byte_row_uhc_2 (int byte) {
  1055.   if (byte >= 0xa1 && byte < 0xff)
  1056.     return byte-0xa1;
  1057.   else
  1058.     return -1;
  1059. }
  1060. static int byte_col_uhc_2 (int byte) {
  1061.   if (byte >= 0x41 && byte < 0x5b)
  1062.     return byte-0x41;
  1063.   else if (byte >= 0x61 && byte < 0x7b)
  1064.     return byte-0x47;
  1065.   else if (byte >= 0x81 && byte < 0xa1)
  1066.     return byte-0x4d;
  1067.   else
  1068.     return -1;
  1069. }
  1070.  
  1071. static void do_uhc_2 (const char* name)
  1072. {
  1073.   Encoding enc;
  1074.  
  1075.   enc.rows = 94;
  1076.   enc.cols = 84;
  1077.   enc.row_byte = row_byte_uhc_2;
  1078.   enc.col_byte = col_byte_uhc_2;
  1079.   enc.byte_row = byte_row_uhc_2;
  1080.   enc.byte_col = byte_col_uhc_2;
  1081.   enc.check_row_expr = "(%1$s >= 0xa1 && %1$s < 0xff)";
  1082.   enc.check_col_expr = "(%1$s >= 0x41 && %1$s < 0x5b) || (%1$s >= 0x61 && %1$s < 0x7b) || (%1$s >= 0x81 && %1$s < 0xa1)";
  1083.   enc.byte_row_expr = "%1$s - 0xa1";
  1084.   enc.byte_col_expr = "%1$s - (%1$s >= 0x81 ? 0x4d : %1$s >= 0x61 ? 0x47 : 0x41)";
  1085.  
  1086.   read_table(&enc);
  1087.   output_charset2uni_noholes_monotonic(name,&enc);
  1088.   invert(&enc); output_uni2charset_sparse(name,&enc,true);
  1089. }
  1090.  
  1091. /* Big5 specifics */
  1092.  
  1093. static int row_byte_big5 (int row) {
  1094.   return 0xa1+row;
  1095. }
  1096. static int col_byte_big5 (int col) {
  1097.   return (col >= 0x3f ? 0x62 : 0x40) + col;
  1098. }
  1099. static int byte_row_big5 (int byte) {
  1100.   if (byte >= 0xa1 && byte < 0xff)
  1101.     return byte-0xa1;
  1102.   else
  1103.     return -1;
  1104. }
  1105. static int byte_col_big5 (int byte) {
  1106.   if (byte >= 0x40 && byte < 0x7f)
  1107.     return byte-0x40;
  1108.   else if (byte >= 0xa1 && byte < 0xff)
  1109.     return byte-0x62;
  1110.   else
  1111.     return -1;
  1112. }
  1113.  
  1114. static void do_big5 (const char* name)
  1115. {
  1116.   Encoding enc;
  1117.  
  1118.   enc.rows = 94;
  1119.   enc.cols = 157;
  1120.   enc.row_byte = row_byte_big5;
  1121.   enc.col_byte = col_byte_big5;
  1122.   enc.byte_row = byte_row_big5;
  1123.   enc.byte_col = byte_col_big5;
  1124.   enc.check_row_expr = "%1$s >= 0xa1 && %1$s < 0xff";
  1125.   enc.check_col_expr = "(%1$s >= 0x40 && %1$s < 0x7f) || (%1$s >= 0xa1 && %1$s < 0xff)";
  1126.   enc.byte_row_expr = "%1$s - 0xa1";
  1127.   enc.byte_col_expr = "%1$s - (%1$s >= 0xa1 ? 0x62 : 0x40)";
  1128.  
  1129.   read_table(&enc);
  1130.   output_charset2uni(name,&enc);
  1131.   invert(&enc); output_uni2charset_sparse(name,&enc,false);
  1132. }
  1133.  
  1134. /* HKSCS specifics */
  1135.  
  1136. static int row_byte_hkscs (int row) {
  1137.   return 0x80+row;
  1138. }
  1139. static int byte_row_hkscs (int byte) {
  1140.   if (byte >= 0x80 && byte < 0xff)
  1141.     return byte-0x80;
  1142.   else
  1143.     return -1;
  1144. }
  1145.  
  1146. static void do_hkscs (const char* name)
  1147. {
  1148.   Encoding enc;
  1149.  
  1150.   enc.rows = 128;
  1151.   enc.cols = 157;
  1152.   enc.row_byte = row_byte_hkscs;
  1153.   enc.col_byte = col_byte_big5;
  1154.   enc.byte_row = byte_row_hkscs;
  1155.   enc.byte_col = byte_col_big5;
  1156.   enc.check_row_expr = "%1$s >= 0x80 && %1$s < 0xff";
  1157.   enc.check_col_expr = "(%1$s >= 0x40 && %1$s < 0x7f) || (%1$s >= 0xa1 && %1$s < 0xff)";
  1158.   enc.byte_row_expr = "%1$s - 0x80";
  1159.   enc.byte_col_expr = "%1$s - (%1$s >= 0xa1 ? 0x62 : 0x40)";
  1160.  
  1161.   read_table(&enc);
  1162.   output_charset2uni(name,&enc);
  1163.   invert(&enc); output_uni2charset_sparse(name,&enc,false);
  1164. }
  1165.  
  1166. /* Johab Hangul specifics */
  1167.  
  1168. static int row_byte_johab_hangul (int row) {
  1169.   return 0x84+row;
  1170. }
  1171. static int col_byte_johab_hangul (int col) {
  1172.   return (col >= 0x3e ? 0x43 : 0x41) + col;
  1173. }
  1174. static int byte_row_johab_hangul (int byte) {
  1175.   if (byte >= 0x84 && byte < 0xd4)
  1176.     return byte-0x84;
  1177.   else
  1178.     return -1;
  1179. }
  1180. static int byte_col_johab_hangul (int byte) {
  1181.   if (byte >= 0x41 && byte < 0x7f)
  1182.     return byte-0x41;
  1183.   else if (byte >= 0x81 && byte < 0xff)
  1184.     return byte-0x43;
  1185.   else
  1186.     return -1;
  1187. }
  1188.  
  1189. static void do_johab_hangul (const char* name)
  1190. {
  1191.   Encoding enc;
  1192.  
  1193.   enc.rows = 80;
  1194.   enc.cols = 188;
  1195.   enc.row_byte = row_byte_johab_hangul;
  1196.   enc.col_byte = col_byte_johab_hangul;
  1197.   enc.byte_row = byte_row_johab_hangul;
  1198.   enc.byte_col = byte_col_johab_hangul;
  1199.   enc.check_row_expr = "%1$s >= 0x84 && %1$s < 0xd4";
  1200.   enc.check_col_expr = "(%1$s >= 0x41 && %1$s < 0x7f) || (%1$s >= 0x81 && %1$s < 0xff)";
  1201.   enc.byte_row_expr = "%1$s - 0x84";
  1202.   enc.byte_col_expr = "%1$s - (%1$s >= 0x81 ? 0x43 : 0x41)";
  1203.  
  1204.   read_table(&enc);
  1205.   output_charset2uni(name,&enc);
  1206.   invert(&enc); output_uni2charset_dense(name,&enc);
  1207. }
  1208.  
  1209. /* SJIS specifics */
  1210.  
  1211. static int row_byte_sjis (int row) {
  1212.   return (row >= 0x1f ? 0xc1 : 0x81) + row;
  1213. }
  1214. static int col_byte_sjis (int col) {
  1215.   return (col >= 0x3f ? 0x41 : 0x40) + col;
  1216. }
  1217. static int byte_row_sjis (int byte) {
  1218.   if (byte >= 0x81 && byte < 0xa0)
  1219.     return byte-0x81;
  1220.   else if (byte >= 0xe0)
  1221.     return byte-0xc1;
  1222.   else
  1223.     return -1;
  1224. }
  1225. static int byte_col_sjis (int byte) {
  1226.   if (byte >= 0x40 && byte < 0x7f)
  1227.     return byte-0x40;
  1228.   else if (byte >= 0x80 && byte < 0xfd)
  1229.     return byte-0x41;
  1230.   else
  1231.     return -1;
  1232. }
  1233.  
  1234. static void do_sjis (const char* name)
  1235. {
  1236.   Encoding enc;
  1237.  
  1238.   enc.rows = 94;
  1239.   enc.cols = 188;
  1240.   enc.row_byte = row_byte_sjis;
  1241.   enc.col_byte = col_byte_sjis;
  1242.   enc.byte_row = byte_row_sjis;
  1243.   enc.byte_col = byte_col_sjis;
  1244.   enc.check_row_expr = "(%1$s >= 0x81 && %1$s < 0xa0) || (%1$s >= 0xe0)";
  1245.   enc.check_col_expr = "(%1$s >= 0x40 && %1$s < 0x7f) || (%1$s >= 0x80 && %1$s < 0xfd)";
  1246.   enc.byte_row_expr = "%1$s - (%1$s >= 0xe0 ? 0xc1 : 0x81)";
  1247.   enc.byte_col_expr = "%1$s - (%1$s >= 0x80 ? 0x41 : 0x40)";
  1248.  
  1249.   read_table(&enc);
  1250.   output_charset2uni(name,&enc);
  1251.   invert(&enc); output_uni2charset_sparse(name,&enc,false);
  1252. }
  1253.  
  1254. /* GB18030 Unicode specifics */
  1255.  
  1256. static void do_gb18030uni (const char* name)
  1257. {
  1258.   int c;
  1259.   unsigned int bytes;
  1260.   int i1, i2, i3, i4, i, j, k;
  1261.   int charset2uni[4*10*126*10];
  1262.   int uni2charset[0x10000];
  1263.   struct { int low; int high; int diff; int total; } ranges[256];
  1264.   int ranges_count, ranges_total;
  1265.  
  1266.   for (i = 0; i < 4*10*126*10; i++)
  1267.     charset2uni[i] = 0;
  1268.   for (j = 0; j < 0x10000; j++)
  1269.     uni2charset[j] = 0;
  1270.  
  1271.   /* Read a unicode.org style .TXT file. */
  1272.   for (;;) {
  1273.     c = getc(stdin);
  1274.     if (c == EOF)
  1275.       break;
  1276.     if (c == '\n' || c == ' ' || c == '\t')
  1277.       continue;
  1278.     if (c == '#') {
  1279.       do { c = getc(stdin); } while (!(c == EOF || c == '\n'));
  1280.       continue;
  1281.     }
  1282.     ungetc(c,stdin);
  1283.     if (scanf("0x%x", &bytes) != 1)
  1284.       exit(1);
  1285.     i1 = (bytes >> 24) & 0xff;
  1286.     i2 = (bytes >> 16) & 0xff;
  1287.     i3 = (bytes >> 8) & 0xff;
  1288.     i4 = bytes & 0xff;
  1289.     if (!(i1 >= 0x81 && i1 <= 0x84
  1290.           && i2 >= 0x30 && i2 <= 0x39
  1291.           && i3 >= 0x81 && i3 <= 0xfe
  1292.           && i4 >= 0x30 && i4 <= 0x39)) {
  1293.       fprintf(stderr, "lost entry for %02x %02x %02x %02x\n", i1, i2, i3, i4);
  1294.       exit(1);
  1295.     }
  1296.     i = (((i1-0x81) * 10 + (i2-0x30)) * 126 + (i3-0x81)) * 10 + (i4-0x30);
  1297.     if (scanf(" 0x%x", &j) != 1)
  1298.       exit(1);
  1299.     if (!(j >= 0 && j < 0x10000))
  1300.       exit(1);
  1301.     charset2uni[i] = j;
  1302.     uni2charset[j] = i;
  1303.   }
  1304.  
  1305.   /* Verify that the mapping i -> j is monotonically increasing and
  1306.      of the form
  1307.         low[k] <= i <= high[k]  =>  j = diff[k] + i
  1308.      with a set of disjoint intervals (low[k], high[k]). */
  1309.   ranges_count = 0;
  1310.   for (i = 0; i < 4*10*126*10; i++)
  1311.     if (charset2uni[i] != 0) {
  1312.       int diff;
  1313.       j = charset2uni[i];
  1314.       diff = j - i;
  1315.       if (ranges_count > 0) {
  1316.         if (!(i > ranges[ranges_count-1].high))
  1317.           exit(1);
  1318.         if (!(j > ranges[ranges_count-1].high + ranges[ranges_count-1].diff))
  1319.           exit(1);
  1320.         /* Additional property: The diffs are also increasing. */
  1321.         if (!(diff >= ranges[ranges_count-1].diff))
  1322.           exit(1);
  1323.       }
  1324.       if (ranges_count > 0 && diff == ranges[ranges_count-1].diff)
  1325.         ranges[ranges_count-1].high = i;
  1326.       else {
  1327.         if (ranges_count == 256)
  1328.           exit(1);
  1329.         ranges[ranges_count].low = i;
  1330.         ranges[ranges_count].high = i;
  1331.         ranges[ranges_count].diff = diff;
  1332.         ranges_count++;
  1333.       }
  1334.     }
  1335.  
  1336.   /* Determine size of bitmap. */
  1337.   ranges_total = 0;
  1338.   for (k = 0; k < ranges_count; k++) {
  1339.     ranges[k].total = ranges_total;
  1340.     ranges_total += ranges[k].high - ranges[k].low + 1;
  1341.   }
  1342.  
  1343.   printf("static const unsigned short %s_charset2uni_ranges[%d] = {\n", name, 2*ranges_count);
  1344.   for (k = 0; k < ranges_count; k++) {
  1345.     printf("  0x%04x, 0x%04x", ranges[k].low, ranges[k].high);
  1346.     if (k+1 < ranges_count) printf(",");
  1347.     if ((k % 4) == 3 && k+1 < ranges_count) printf("\n");
  1348.   }
  1349.   printf("\n");
  1350.   printf("};\n");
  1351.  
  1352.   printf("\n");
  1353.  
  1354.   printf("static const unsigned short %s_uni2charset_ranges[%d] = {\n", name, 2*ranges_count);
  1355.   for (k = 0; k < ranges_count; k++) {
  1356.     printf("  0x%04x, 0x%04x", ranges[k].low + ranges[k].diff, ranges[k].high + ranges[k].diff);
  1357.     if (k+1 < ranges_count) printf(",");
  1358.     if ((k % 4) == 3 && k+1 < ranges_count) printf("\n");
  1359.   }
  1360.   printf("\n");
  1361.   printf("};\n");
  1362.  
  1363.   printf("\n");
  1364.  
  1365.   printf("static const struct { unsigned short diff; unsigned short bitmap_offset; } %s_ranges[%d] = {\n ", name, ranges_count);
  1366.   for (k = 0; k < ranges_count; k++) {
  1367.     printf(" { %5d, 0x%04x }", ranges[k].diff, ranges[k].total);
  1368.     if (k+1 < ranges_count) printf(",");
  1369.     if ((k % 4) == 3 && k+1 < ranges_count) printf("\n ");
  1370.   }
  1371.   printf("\n");
  1372.   printf("};\n");
  1373.  
  1374.   printf("\n");
  1375.  
  1376.   printf("static const unsigned char %s_bitmap[%d] = {\n ", name, (ranges_total + 7) / 8);
  1377.   {
  1378.     int accu = 0;
  1379.     for (k = 0; k < ranges_count; k++) {
  1380.       for (i = ranges[k].total; i <= ranges[k].total + (ranges[k].high - ranges[k].low);) {
  1381.         if (charset2uni[i - ranges[k].total + ranges[k].low] != 0)
  1382.           accu |= (1 << (i % 8));
  1383.         i++;
  1384.         if ((i % 8) == 0) {
  1385.           printf(" 0x%02x", accu);
  1386.           if ((i / 8) < (ranges_total + 7) / 8) printf(",");
  1387.           if (((i / 8) % 12) == 0)
  1388.             printf("\n ");
  1389.           accu = 0;
  1390.         }
  1391.       }
  1392.       if (i != (k+1 < ranges_count ? ranges[k+1].total : ranges_total)) abort();
  1393.     }
  1394.     if ((ranges_total % 8) != 0)
  1395.       printf(" 0x%02x", accu);
  1396.     printf("\n");
  1397.   }
  1398.   printf("};\n");
  1399.  
  1400.   printf("\n");
  1401.  
  1402.   printf("static int\n");
  1403.   printf("%s_mbtowc (conv_t conv, wchar_t *pwc, const unsigned char *s, int n)\n", name);
  1404.   printf("{\n");
  1405.   printf("  unsigned char c1 = s[0];\n");
  1406.   printf("  if (c1 >= 0x81 && c1 <= 0x84) {\n");
  1407.   printf("    if (n >= 2) {\n");
  1408.   printf("      unsigned char c2 = s[1];\n");
  1409.   printf("      if (c2 >= 0x30 && c2 <= 0x39) {\n");
  1410.   printf("        if (n >= 3) {\n");
  1411.   printf("          unsigned char c3 = s[2];\n");
  1412.   printf("          if (c3 >= 0x81 && c3 <= 0xfe) {\n");
  1413.   printf("            if (n >= 4) {\n");
  1414.   printf("              unsigned char c4 = s[3];\n");
  1415.   printf("              if (c4 >= 0x30 && c4 <= 0x39) {\n");
  1416.   printf("                unsigned int i = (((c1 - 0x81) * 10 + (c2 - 0x30)) * 126 + (c3 - 0x81)) * 10 + (c4 - 0x30);\n");
  1417.   printf("                if (i >= %d && i <= %d) {\n", ranges[0].low, ranges[ranges_count-1].high);
  1418.   printf("                  unsigned int k1 = 0;\n");
  1419.   printf("                  unsigned int k2 = %d;\n", ranges_count-1);
  1420.   printf("                  while (k1 < k2) {\n");
  1421.   printf("                    unsigned int k = (k1 + k2) / 2;\n");
  1422.   printf("                    if (i <= %s_charset2uni_ranges[2*k+1])\n", name);
  1423.   printf("                      k2 = k;\n");
  1424.   printf("                    else if (i >= %s_charset2uni_ranges[2*k+2])\n", name);
  1425.   printf("                      k1 = k + 1;\n");
  1426.   printf("                    else\n");
  1427.   printf("                      return RET_ILSEQ;\n");
  1428.   printf("                  }\n");
  1429.   printf("                  {\n");
  1430.   printf("                    unsigned int bitmap_index = i - %s_charset2uni_ranges[2*k1] + %s_ranges[k1].bitmap_offset;\n", name, name);
  1431.   printf("                    if ((%s_bitmap[bitmap_index >> 3] >> (bitmap_index & 7)) & 1) {\n", name);
  1432.   printf("                      unsigned int diff = %s_ranges[k1].diff;\n", name);
  1433.   printf("                      *pwc = (wchar_t) (i + diff);\n");
  1434.   printf("                      return 4;\n");
  1435.   printf("                    }\n");
  1436.   printf("                  }\n");
  1437.   printf("                }\n");
  1438.   printf("              }\n");
  1439.   printf("              return RET_ILSEQ;\n");
  1440.   printf("            }\n");
  1441.   printf("            return RET_TOOFEW(0);\n");
  1442.   printf("          }\n");
  1443.   printf("          return RET_ILSEQ;\n");
  1444.   printf("        }\n");
  1445.   printf("        return RET_TOOFEW(0);\n");
  1446.   printf("      }\n");
  1447.   printf("      return RET_ILSEQ;\n");
  1448.   printf("    }\n");
  1449.   printf("    return RET_TOOFEW(0);\n");
  1450.   printf("  }\n");
  1451.   printf("  return RET_ILSEQ;\n");
  1452.   printf("}\n");
  1453.  
  1454.   printf("\n");
  1455.  
  1456.   printf("static int\n");
  1457.   printf("%s_wctomb (conv_t conv, unsigned char *r, wchar_t wc, int n)\n", name);
  1458.   printf("{\n");
  1459.   printf("  if (n >= 4) {\n");
  1460.   printf("    unsigned int i = wc;\n");
  1461.   printf("    if (i >= 0x%04x && i <= 0x%04x) {\n", ranges[0].low + ranges[0].diff, ranges[ranges_count-1].high + ranges[ranges_count-1].diff);
  1462.   printf("      unsigned int k1 = 0;\n");
  1463.   printf("      unsigned int k2 = %d;\n", ranges_count-1);
  1464.   printf("      while (k1 < k2) {\n");
  1465.   printf("        unsigned int k = (k1 + k2) / 2;\n");
  1466.   printf("        if (i <= %s_uni2charset_ranges[2*k+1])\n", name);
  1467.   printf("          k2 = k;\n");
  1468.   printf("        else if (i >= %s_uni2charset_ranges[2*k+2])\n", name);
  1469.   printf("          k1 = k + 1;\n");
  1470.   printf("        else\n");
  1471.   printf("          return RET_ILSEQ;\n");
  1472.   printf("      }\n");
  1473.   printf("      {\n");
  1474.   printf("        unsigned int bitmap_index = i - %s_uni2charset_ranges[2*k1] + %s_ranges[k1].bitmap_offset;\n", name, name);
  1475.   printf("        if ((%s_bitmap[bitmap_index >> 3] >> (bitmap_index & 7)) & 1) {\n", name);
  1476.   printf("          unsigned int diff = %s_ranges[k1].diff;\n", name);
  1477.   printf("          i -= diff;\n");
  1478.   printf("          r[3] = (i %% 10) + 0x30; i = i / 10;\n");
  1479.   printf("          r[2] = (i %% 126) + 0x81; i = i / 126;\n");
  1480.   printf("          r[1] = (i %% 10) + 0x30; i = i / 10;\n");
  1481.   printf("          r[0] = i + 0x81;\n");
  1482.   printf("          return 4;\n");
  1483.   printf("        }\n");
  1484.   printf("      }\n");
  1485.   printf("    }\n");
  1486.   printf("    return RET_ILSEQ;\n");
  1487.   printf("  }\n");
  1488.   printf("  return RET_TOOSMALL;\n");
  1489.   printf("}\n");
  1490. }
  1491.  
  1492. /* Main program */
  1493.  
  1494. int main (int argc, char *argv[])
  1495. {
  1496.   const char* charsetname;
  1497.   const char* name;
  1498.  
  1499.   if (argc != 3)
  1500.     exit(1);
  1501.   charsetname = argv[1];
  1502.   name = argv[2];
  1503.  
  1504.   output_title(charsetname);
  1505.  
  1506.   if (!strcmp(name,"gb2312")
  1507.       || !strcmp(name,"isoir165ext") || !strcmp(name,"gb12345ext")
  1508.       || !strcmp(name,"jisx0208") || !strcmp(name,"jisx0212"))
  1509.     do_normal(name);
  1510.   else if (!strcmp(name,"cns11643_1") || !strcmp(name,"cns11643_2")
  1511.            || !strcmp(name,"cns11643_3"))
  1512.     do_normal_only_charset2uni(name);
  1513.   else if (!strcmp(name,"cns11643_inv"))
  1514.     do_cns11643_only_uni2charset(name);
  1515.   else if (!strcmp(name,"gbkext1"))
  1516.     do_gbk1_only_charset2uni(name);
  1517.   else if (!strcmp(name,"gbkext2"))
  1518.     do_gbk2_only_charset2uni(name);
  1519.   else if (!strcmp(name,"gbkext_inv"))
  1520.     do_gbk1_only_uni2charset(name);
  1521.   else if (!strcmp(name,"cp936ext") || !strcmp(name,"gb18030ext"))
  1522.     do_gbk1(name);
  1523.   else if (!strcmp(name,"ksc5601"))
  1524.     do_ksc5601(name);
  1525.   else if (!strcmp(name,"uhc_1"))
  1526.     do_uhc_1(name);
  1527.   else if (!strcmp(name,"uhc_2"))
  1528.     do_uhc_2(name);
  1529.   else if (!strcmp(name,"big5") || !strcmp(name,"cp950ext"))
  1530.     do_big5(name);
  1531.   else if (!strcmp(name,"hkscs"))
  1532.     do_hkscs(name);
  1533.   else if (!strcmp(name,"johab_hangul"))
  1534.     do_johab_hangul(name);
  1535.   else if (!strcmp(name,"cp932ext"))
  1536.     do_sjis(name);
  1537.   else if (!strcmp(name,"gb18030uni"))
  1538.     do_gb18030uni(name);
  1539.   else
  1540.     exit(1);
  1541.  
  1542.   return 0;
  1543. }
  1544.